<?php
class TreeService extends AbstractService{
    private static $instance;

    public static function get() {
        if (!self::$instance) {
            self::$instance = new TreeService();
        }
        return self::$instance;
    }

    protected function __construct() {
        parent::__construct();
    }

    public function handleCreate($userId) {

    }

    public function handleLogin($userId) {

    }

    public function info($userId) {
        return $this->initTree($userId);
    }

    /**
     * 任务升级树
     * @param $userId
     * @param $buildingId
     * @return array
     * @throws SzException
     */
    public function upTree($userId,$buildingId) {
        $treeGrowthInfoSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GAME_TREE_GROWTH_INFO, $buildingId, true);
        if (!$treeGrowthInfoSetting) {
            throw new SzException(80001,GameConst::CONFIG_GAME_TREE_GROWTH_INFO.'-'.$buildingId);
        }

        $nextBuildingId = $treeGrowthInfoSetting['nextBuildingId'];
        if (!$nextBuildingId) {
            throw new SzException(90063);
        }

        /**
         * @var $userTreeInfoList TreeInfoVoList
         * @var $userTreeInfo TreeInfoVo
         */
        $userTreeInfoList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_TREE_INFO);
        $userTreeInfoList->getElement($buildingId);

        /**
         * @var $userTreeTakProgressList TreeTakProgressVoList
         * @var $userTreeTakProgress TreeTakProgressVo
         */
        $userTreeTakProgressList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_TREE_TASK_PROGRESS);

        foreach ($treeGrowthInfoSetting['taskIds']as $taskId) {
            $treeTaskInfoSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GAME_TREE_TASK_INFO, $taskId, true);
            if (!$treeTaskInfoSetting) {
                throw new SzException(80001,GameConst::CONFIG_GAME_TREE_TASK_INFO.'-'.$taskId);
            }

            $userTreeTakProgress = $userTreeTakProgressList->getElement($treeTaskInfoSetting['taskType'],false);
            if (!$userTreeTakProgress) {
                throw new SzException(90051);
            }

            if ($userTreeTakProgress->getProgress() < $treeTaskInfoSetting['count']) {
                throw new SzException(90051);
            }
        }

        $userTreeInfoList->deleteElement($buildingId);
        $userTreeInfo = new TreeInfoVo($userId,$nextBuildingId,0,1,0,0,0,true);
        $userTreeInfoList->addElement($userTreeInfo);
        $userTreeInfoList->setElement($nextBuildingId,$userTreeInfo);
        SzPersister::get()->setVoList($userTreeInfoList);

        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_USER_ORBIT, array(
            'clientData' => array(
                'tid' => 'Module:expTree|action:grow|',
                'item' => $nextBuildingId,
                'value' => 1
            )
        ));

        return $userTreeInfo->toArray();
    }

    /**
     * 更新任务进度
     * @param $userId
     * @param $progress
     * @param $content
     * @throws SzException
     */
    public function setProgress($userId,$content,$progress) {
        if (!GameService::get()->verifySysUnlock($userId, GameConst::FUNC_TREE,true)) {
            return;
        }
        /**
         * @var $userTreeTakProgressList TreeTakProgressVoList
         * @var $userTreeTakProgress TreeTakProgressVo
         */
        $userTreeTakProgressList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_TREE_TASK_PROGRESS);
        $userTreeTakProgress = $userTreeTakProgressList->getElement($content,false);
        if ($userTreeTakProgress) {
            if ($userTreeTakProgress->getProgress() > 99999999) {
                return;
            }
            $userTreeTakProgress->setProgress($progress);
            $userTreeTakProgressList->updateElement($content,$userTreeTakProgress);
        } else {
            $userTreeTakProgress = new TreeTakProgressVo($userId,$content,$progress,true);
            $userTreeTakProgressList->addElement($userTreeTakProgress);
            $userTreeTakProgressList->setElement($content,$userTreeTakProgress);
        }
        SzPersister::get()->setVoList($userTreeTakProgressList);
        return;
    }

    /**
     * 更新任务进度
     * @param $userId
     * @param $progress
     * @param $content
     * @throws SzException
     */
    public function updateProgress($userId,$content,$progress) {
        if (!GameService::get()->verifySysUnlock($userId, GameConst::FUNC_TREE,true)) {
            return;
        }
        /**
         * @var $userTreeTakProgressList TreeTakProgressVoList
         * @var $userTreeTakProgress TreeTakProgressVo
         */
        $userTreeTakProgressList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_TREE_TASK_PROGRESS);
        $userTreeTakProgress = $userTreeTakProgressList->getElement($content,false);
        if ($userTreeTakProgress) {
            if ($userTreeTakProgress->getProgress() > 99999999) {
                return;
            }
            $userTreeTakProgress->updateProgress($progress);
            if ($_SERVER['is_payment_callback'] ?? false) $userTreeTakProgress->persist();
            $userTreeTakProgressList->updateElement($content,$userTreeTakProgress);
        } else {
            $userTreeTakProgress = new TreeTakProgressVo($userId,$content,$progress,true);
            $userTreeTakProgressList->addElement($userTreeTakProgress);
            $userTreeTakProgressList->setElement($content,$userTreeTakProgress);
            if ($_SERVER['is_payment_callback'] ?? false) $userTreeTakProgressList->persist();
        }
        SzPersister::get()->setVoList($userTreeTakProgressList);
        return;
    }

    /**
     * 初始化树
     * @param $userId
     * @return array
     * @throws SzException
     */
    public function initTree($userId) {
        $info = array();
        $userTreeInfoList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_TREE_INFO);
        if (!count($userTreeInfoList->toArray())) {
            $treeInitBuildingId = SzConfig::get()->loadAppConfig(ModuleProfileConst::CONFIG_PROFILE, 'treeInitBuildingId', true);
            if (!$treeInitBuildingId) {
                return $info;
            }
            $userTreeInfo = new TreeInfoVo($userId,$treeInitBuildingId['value'],0,1,0,0,0,true);
            $userTreeInfoList->addElement($userTreeInfo);
            $userTreeInfoList->setElement($treeInitBuildingId['value'],$userTreeInfo);
            SzPersister::get()->setVoList($userTreeInfoList);
            $info = $userTreeInfo->toArray();
        } else {
            foreach ($userTreeInfoList->toArray() as $v) {
                $info = $v;
                break;
            }
        }

        return $info;
    }

    /**
     * 使用道具
     * @param $userId
     * @param $buildingId
     * @param $itemIds
     * @param $reqTime
     * @return array
     * @throws SzException
     */
    public function useCultivationItem($userId,$buildingId,$itemIds,$reqTime) {
        $totalNum = count($itemIds);

        if ($totalNum < 1 || $totalNum > 5) {
            throw new SzException(90064);
        }

        $treeGrowthInfoSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GAME_TREE_GROWTH_INFO, $buildingId, true);
        if (!$treeGrowthInfoSetting) {
            throw new SzException(80001,GameConst::CONFIG_GAME_TREE_GROWTH_INFO.'-'.$buildingId);
        }

        $nextBuildingId = $treeGrowthInfoSetting['nextBuildingId'];
        if ($nextBuildingId) {
            throw new SzException(90063);
        }

        /**
         * @var $userTreeInfoList TreeInfoVoList
         * @var $userTreeInfo TreeInfoVo
         */
        $userTreeInfoList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_TREE_INFO);
        $userTreeInfo = $userTreeInfoList->getElement($buildingId);

        $level = $userTreeInfo->getLevel();
        $treeUpgradeSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GAME_TREE_UPGRADE, $level, true);
        if (!$treeUpgradeSetting) {
            throw new SzException(80001,GameConst::CONFIG_GAME_TREE_UPGRADE.'-'.$level);
        }

        $userLevel = UserService::get()->getUserLevel($userId);
        $treeGainExperienceSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GAME_TREE_GAIN_EXPERIENCE, $userLevel, true);
        if (!$treeGainExperienceSetting) {
            throw new SzException(80001,GameConst::CONFIG_GAME_TREE_GAIN_EXPERIENCE.'-'.$userLevel);
        }

        $productionTime = SzConfig::get()->loadAppConfig(ModuleProfileConst::CONFIG_PROFILE, 'ProductionTime', true);
        if (!$productionTime) {
            throw new SzException(90063);
        }

        $productionTime = $productionTime['value'];

        $treePropSettings = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GAME_TREE_PROP, null, true);
        $addTime = 0;
        $input = '';
        foreach ($itemIds as $itemId) {
            if (!isset($treePropSettings[$itemId])) {
                throw new SzException(80001,GameConst::CONFIG_GAME_TREE_PROP.'-'.$itemId);
            }
            $entityId = EntityService::get()->buildEntityId(GameConst::ENTITY_ACTION_CONSUME, GameConst::ENTITY_TYPE_ITEM, $itemId);
            GameService::get()->handleEntity($userId, $entityId, 1, true);
            $input .= $entityId.':1|';
            $addTime += $treePropSettings[$itemId]['time'];
        }
        CommonFunctionService::get()->reportResourceUseDetails(GameConst::FUNC_TREE,$userId,0,$input,'useCultivationItem');//消耗资源上报

        if ($userTreeInfo->getEndTime()) {
            throw new SzException(90067);
        }

        $endTime = $reqTime + $addTime;
        $number = $userTreeInfo->getNumber() + $totalNum;

        $count = $addTime / $productionTime * ($treeGainExperienceSetting['experience'] + $treeUpgradeSetting['addition']);

        if ($treeUpgradeSetting['demand']) {
            $userTreeInfo->setNumber($number);
        }

        $newLevel = $level;

        if ($number >= $treeUpgradeSetting['demand'] && $treeUpgradeSetting['demand']) {
            $newLevel = $level + 1;
            $userTreeInfo->setLevel($newLevel);
        }

        $userTreeInfo->setEndTime($endTime);
        $userTreeInfo->setExp($count);
        $userTreeInfo->setStartTime($reqTime);

        $userTreeInfoList->updateElement($buildingId,$userTreeInfo);
        SzPersister::get()->setVoList($userTreeInfoList);

        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_USER_ORBIT, array(
            'clientData' => array(
                'tid' => 'Module:expTree|action:upgrade|',
                'item' => 'expTree_upgrade',
                'value' => 1
            )
        ));

        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_UPGRADE, array(
            'clientData' => array(
                'tid' => 'objective:book|item:|'.$buildingId,
                'item' => 'fromlevel:'.$level.'|changelev:'.($newLevel-$level).'|targetlev:'.$newLevel.'|',
                'value' => 1
            )
        ));

        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_RESOURCE_INPUT, array(
            'clientData' => array(
                'tid' => $input,
                'item' => 'expTree_upgrade',
                'value' => 1
            )
        ));

        return $userTreeInfo->toArray();
    }

    /**
     * 领取经验
     * @param $userId
     * @param $buildingId
     * @param $reqTime
     * @return bool
     * @throws SzException
     */
    public function getReward($userId,$buildingId,$reqTime) {
        /**
         * @var $userTreeInfoList TreeInfoVoList
         * @var $userTreeInfo TreeInfoVo
         */
        $userTreeInfoList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_TREE_INFO);
        $userTreeInfo = $userTreeInfoList->getElement($buildingId);

        $endTime = $userTreeInfo->getEndTime();

        if (!$endTime) {
            throw new SzException(90065); // 当前为空不可领取
        }

        if ($reqTime < $endTime) {
            throw new SzException(90065); // 时间未到不可领取
        }

        $count = $userTreeInfo->getExp();
        GameService::get()->handleEntity($userId, GameConst::ENTITY_ACTION_GET_EXP, $count, true);
        CommonFunctionService::get()->reportResourceUseDetails(GameConst::FUNC_TREE,$userId,1,GameConst::ENTITY_ACTION_GET_EXP.':'.$count.'|','getReward');//获得资源上报


        $userTreeInfo->setExp(0);
        $userTreeInfo->setEndTime(0);
        $userTreeInfo->setStartTime(0);

        $userTreeInfoList->updateElement($buildingId,$userTreeInfo);
        SzPersister::get()->setVoList($userTreeInfoList);

        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_USER_ORBIT, array(
            'clientData' => array(
                'tid' => 'Module:expTree|action:exp|',
                'item' => $count,
                'value' => 1
            )
        ));

        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_RESOURCE_OUTPUT, array(
            'clientData' => array(
                'tid' => GameConst::ENTITY_ACTION_GET_EXP.':'.$count.'|',
                'item' => 'expTree_exp',
                'value' => 1
            )
        ));

        return true;
    }

    /**
     * 获取任务进度
     * @param $userId
     * @return array
     */
    public function getProgress($userId) {
        $userTreeTakProgressList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_TREE_TASK_PROGRESS);
        return $userTreeTakProgressList->toArray();
    }
}
